﻿using System;
using System.Collections.Generic;

namespace Patterns.Builder {

    public class AppliedExample {

        public static void Run() {
            // Create shop with vehicle builders
            Shop shop = new Shop();
            VehicleBuilder b1 = new ScooterBuilder();
            VehicleBuilder b2 = new CarBuilder();
            VehicleBuilder b3 = new MotorCycleBuilder();

            // Construct and display vehicles
            shop.Construct(b1);
            b1.Vehicle.Show();

            shop.Construct(b2);
            b2.Vehicle.Show();

            shop.Construct(b3);
            b3.Vehicle.Show();
        }

        // "Director"
        private class Shop {
            // Builder uses a complex series of steps
            public void Construct(VehicleBuilder vehicleBuilder) {
                vehicleBuilder.BuildFrame();
                vehicleBuilder.BuildEngine();
                vehicleBuilder.BuildWheels();
                vehicleBuilder.BuildDoors();
            }
        }

        // "Builder"
        private abstract class VehicleBuilder {

            // Property
            public Vehicle Vehicle { get; protected set; }

            public abstract void BuildFrame();
            public abstract void BuildEngine();
            public abstract void BuildWheels();
            public abstract void BuildDoors();
        }

        // "ConcreteBuilder1"
        private class MotorCycleBuilder : VehicleBuilder {
            public override void BuildFrame() {
                Vehicle = new Vehicle("MotorCycle");
                Vehicle["frame"] = "MotorCycle Frame";
            }

            public override void BuildEngine() {
                Vehicle["engine"] = "500 cc";
            }

            public override void BuildWheels() {
                Vehicle["wheels"] = "2";
            }

            public override void BuildDoors() {
                Vehicle["doors"] = "0";
            }
        }

        // "ConcreteBuilder2"
        private class CarBuilder : VehicleBuilder {
            public override void BuildFrame() {
                Vehicle = new Vehicle("Car");
                Vehicle["frame"] = "Car Frame";
            }

            public override void BuildEngine() {
                Vehicle["engine"] = "2500 cc";
            }

            public override void BuildWheels() {
                Vehicle["wheels"] = "4";
            }

            public override void BuildDoors() {
                Vehicle["doors"] = "4";
            }
        }

        // "ConcreteBuilder3"
        private class ScooterBuilder : VehicleBuilder {
            public override void BuildFrame() {
                Vehicle = new Vehicle("Scooter");
                Vehicle["frame"] = "Scooter Frame";
            }

            public override void BuildEngine() {
                Vehicle["engine"] = "50 cc";
            }

            public override void BuildWheels() {
                Vehicle["wheels"] = "2";
            }

            public override void BuildDoors() {
                Vehicle["doors"] = "0";
            }
        }

        // "Product"
        private class Vehicle {
            private string type;
            private Dictionary<string, object> parts = new Dictionary<string, object>();

            // Constructor
            public Vehicle(string type) {
                this.type = type;
            }

            // Indexer (i.e. smart array)
            public object this[string key] {
                get { return parts[key]; }
                set { parts[key] = value; }
            }

            public void Show() {
                Console.WriteLine("\n---------------------------");
                Console.WriteLine("Vehicle Type: {0}", type);
                Console.WriteLine(" Frame : {0}", parts["frame"]);
                Console.WriteLine(" Engine : {0}", parts["engine"]);
                Console.WriteLine(" #Wheels: {0}", parts["wheels"]);
                Console.WriteLine(" #Doors : {0}", parts["doors"]);
            }
        }
    }
}
